#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>

#include <assert.h>

/* --- Data Structures ---------------------------------------------------- */

struct list_element {
 struct list_element *prev;
 struct list_element *next;
 int value; };

struct list {
 struct list_element *first;
 struct list_element *last; };


/* --- Helper Functions --------------------------------------------------- */

#define INPUT_BUF_SIZE 1024

// custom MALLOC()
void* malloc(unsigned) ;

_Bool nondet_bool();

void* my_malloc (unsigned s) {
  if (nondet_bool()) return NULL;
return malloc(s) ;
}

/* --- List Implementation ------------------------------------------------ */

struct list_element *list_new_elem (int value)
 {
  struct list_element *elem;

  //FIXED
  elem = my_malloc(sizeof (struct list_element));
  if (!elem) { 
	return (NULL); 
  }

  elem->prev = elem;
  elem->next = elem;
  elem->value = value;

  return (elem);
 }

struct list *list_new (void)
 {
  //FIXED
  struct list *list = my_malloc(sizeof (struct list));
  if (list == NULL) { 
	return (NULL); 
  }

  list->first = NULL;
  list->last  = NULL;

  return (list);
 }

void list_append (struct list *list, struct address *addr)
 {
  struct list_element *elem = NULL;

  if (!list) { 
	return; 
  }

  elem = list_new_elem(addr);
  if (!elem) { 
	return; 
  }

  if (list->first == NULL && list->last == NULL)
   {
    list->first = elem;
    list->last  = elem;
    elem->prev  = elem;
    elem->next  = elem;
   }
   else
   {
    elem->prev = list->last;
    elem->next = list->first;
    // FIXED solved the issue a->b->c as described on Toledo
    //FIX list->last->next = elem;
    struct list_element *tmp = list->last;
    tmp->next = elem;
    //FIX list->first->prev = elem;
    tmp = list->first;
    tmp->prev = elem;
    list->last = elem;
   }

  return;
 }

void list_remove (struct list *list, struct list_element *elem)
 {
  if (!elem || !list) { 
	return; 
  }

  if (elem == list->first && elem == list->last)
   {
    list->first = NULL;
    list->last  = NULL;
   }
   else if (elem == list->first)
   {
    list->first = elem->next;     
    // FIXED solved the issue a->b->c as described on Toledo
    struct list_element *tmp = NULL;
    tmp = list->first;
    tmp->prev = list->last;
    //list->first->prev = list->last;
   }
   else if (elem == list->last)
   {
    list->last = elem->prev;
    // FIXED solved the issue a->b->c as described on Toledo
    struct list_element *tmp = NULL;
    tmp = list->last;
    tmp->next = list->first;
    //list->last->next = list->first;
   }
   else
   {
    // FIXED solved the issue a->b->c as described on Toledo
    struct list_element *tmp = NULL;
    tmp = elem->prev;
    tmp->next = elem->next;
    //elem->prev->next = elem->next;
    tmp = elem->next;
    tmp->prev = elem->prev;
    //elem->next->prev = elem->prev;
   }

  //free (elem->addr);   // since we use an integer we don't need to free it explicitly
  free (elem);

  return;
 }

void list_release (struct list *list)
 {
  struct list_element *elem;

  if (!list) { 
	return; 
  }

  elem = list->first;
  while (elem)
   {
    list_remove (list, elem);
    elem = list->first;
   }

  free (list);

  return;
 }

void printList (struct list *list)
 {
  if(list == NULL) {
	return; 
  }
  struct list_element *elem = NULL;
  unsigned int i;

  elem = list->first;
  i = 0;
  while (elem != NULL)
   {
     printf ("%d\n", elem->value);

     if (elem == list->last)
      { elem = NULL; }
      else
      { elem = elem->next; }
     i++; }

  return;
 }
 
void main() {
  struct list *list = NULL;
  list = list_new ();
  list_append(list, 1);
  list_append(list, 2);
  list_append(list, 3);
  
  
  printList(list);
  list_release(list);
 }

